using System;
using System.Drawing;
using System.Windows.Forms;
using CloudShot.Controls;
using CloudShot.Editor;
using CloudShot.Utils;
using CloudShot.Utils.Drawings;

namespace CloudShot.Logic
{
  //TODO rename and move to another folder
  public static class SizeControl
  {
    private const int ControlOffset = 6;
    private static readonly Font _font = new Font(FontFamily.GenericSansSerif, 10);
    private static readonly SolidBrush _rectBrush = new SolidBrush(Color.FromArgb(150, Color.Black));
    private static readonly SolidBrush _textBrush = new SolidBrush(Color.FromArgb(235, 235, 235));
    private static readonly Pen _rectPen = new Pen(Color.FromArgb(90, 90, 90));

    /// <summary>
    /// Draws size control on the <paramref name="graphics"/>.
    /// </summary>
    /// <param name="graphics">The <see cref="Graphics"/> object.</param>
    /// <param name="figureBounds"> The bounds of the figure which size will be shown. </param>
    /// <param name="displayedSize">The size that will be displayed on the control.</param>
    /// <param name="canvasBounds">A bounds of the <see cref="CanvasControl"/>.</param>
    /// <param name="vertex">The vertex index.</param>
    public static void Draw(Graphics graphics, Rectangle figureBounds, Size displayedSize, Rectangle canvasBounds, int vertex)
    {
      const int cornerRadius = 3;
      const TextFormatFlags formatFlags = TextFormatFlags.NoPadding | TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter;

      string label = string.Format("{0} x {1}", Math.Abs(displayedSize.Width), Math.Abs(displayedSize.Height));

      Size labelSize = TextRenderer.MeasureText(graphics, label, _font, Size.Empty, formatFlags);
      labelSize = Size.Add(labelSize, new Size(6, 2));//little bit extend label size for better visualization

      Point position = GetControlPosition(figureBounds, labelSize, canvasBounds, vertex);

      var labelBounds = new Rectangle(position, labelSize);
      graphics.FillRoundedRectangle(_rectBrush, labelBounds, cornerRadius);
      graphics.DrawRoundedRectangle(_rectPen, labelBounds, cornerRadius);
      TextRenderer.DrawText(graphics, label, _font, labelBounds, _textBrush.Color, formatFlags);
    }

    private static Point GetControlPosition(Rectangle cropRect, Size controlSize, Rectangle canvasBounds, int handleNumber)
    {
      Point position = cropRect.GetPointByHandle(handleNumber);

      handleNumber = NormalizeHandle(cropRect, handleNumber);

      Point controlLocation = AlignControl(position, controlSize, handleNumber);

      return RectangleUtils.FitControlToRectangle(controlSize, canvasBounds, controlLocation);;
    }

    

    private static int NormalizeHandle(Rectangle cropRect, int handleNumber)
    {
      if (cropRect.Width >= 0 && cropRect.Height >= 0)
        return handleNumber;

      if (cropRect.Width < 0)
      {
        handleNumber = InvertHorizontally(handleNumber);
      }

      if (cropRect.Height < 0)
      {
        handleNumber = InvertVertically(handleNumber);
      }

      return handleNumber;
    }

    private static int InvertVertically(int handleNumber)
    {
      switch (handleNumber)
      {
        case VertexType.LeftTop:
          return VertexType.LeftBottom;
        case VertexType.RightTop:
          return VertexType.RightBottom;
        case VertexType.Top:
          return VertexType.Bottom;
        case VertexType.RightBottom:
          return VertexType.RightTop;
        case VertexType.LeftBottom:
          return VertexType.LeftTop;
        case VertexType.Bottom:
          return VertexType.Top;
      }
      return handleNumber;
    }

    private static int InvertHorizontally(int handleNumber)
    {
      switch (handleNumber)
      {
        case VertexType.LeftTop:
          return VertexType.RightTop;
        case VertexType.RightTop:
          return VertexType.LeftTop;
        case VertexType.Right:
          return VertexType.Left;
        case VertexType.RightBottom:
          return VertexType.LeftBottom;
        case VertexType.LeftBottom:
          return VertexType.RightBottom;
        case VertexType.Left:
          return VertexType.Right;
      }
      return handleNumber;
    }

    private static Point AlignControl(Point position, Size size, int handleNumber)
    {
      switch (handleNumber)
      {
        case VertexType.LeftTop:
          return new Point(position.X + ControlOffset, position.Y - ControlOffset - size.Height);
        case VertexType.Top:
          return new Point(position.X - size.Width / 2, position.Y - ControlOffset - size.Height);
        case VertexType.RightTop:
          return new Point(position.X - ControlOffset - size.Width, position.Y - ControlOffset - size.Height);
        case VertexType.Right:
          return new Point(position.X + ControlOffset, position.Y - size.Height / 2);
        case VertexType.RightBottom:
          return new Point(position.X - ControlOffset - size.Width, position.Y + ControlOffset);
        case VertexType.Bottom:
          return new Point(position.X - size.Width / 2, position.Y + ControlOffset);
        case VertexType.LeftBottom:
          return new Point(position.X + ControlOffset, position.Y + ControlOffset);
        case VertexType.Left:
          return new Point(position.X - ControlOffset - size.Width, position.Y - size.Height / 2);
      }
      return position;
    }
    
  }
}